Introduction
1. Data Description
1.1. Sample Selected
You can define bullet list or numbered list:
- Pizza
- Pasta
- Cafe
- Espresso
- Macchiato
- Cappuccino
- Vodka
1.3. Import Data (CSV) [*]
data_SD3 <- read.delim("~/RProjects/2024-Q2-R-2 [MDA2024, exercises]/D1_SD3/data_SD3.csv", stringsAsFactors=TRUE)
2. Data Analysis
To add R code in the Notebook we need to use the
Chunk.
X <- iris
It is possible to have an overview of the data by using the
summary function.
summary(X)
Sepal.Length Sepal.Width Petal.Length
Min. :4.300 Min. :2.000 Min. :1.000
1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600
Median :5.800 Median :3.000 Median :4.350
Mean :5.843 Mean :3.057 Mean :3.758
3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100
Max. :7.900 Max. :4.400 Max. :6.900
Petal.Width Species
Min. :0.100 setosa :50
1st Qu.:0.300 versicolor:50
Median :1.300 virginica :50
Mean :1.199
3rd Qu.:1.800
Max. :2.500
In R there are three main type of data:
- Matrix. Mathematical Object. In our example
Y is a matrix.
- Data Frame. It is devoted to organize and analyze
data and it is a generalization of the Matrix. In our example,
X is a data frame.
- List. It is an object that can include Data Frames,
Matrices or other lists.
Y <- as.matrix(X[ ,1:4])
To handle data you can use the following code:
X[10, 2] # selection of one element in the Data Frame (or matrix)
[1] 3.1
X[5:20, 1:3] # selection of an interval
X[5:20, ] # the empty space select all the columns or rows
X$Sepal.Length # the symbol $ is used to select a column in the data frame
[1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8
[14] 4.3 5.8 5.7 5.4 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0
[27] 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4
[40] 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4
[53] 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6
[66] 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7
[79] 6.0 5.7 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5
[92] 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3
[105] 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5
[118] 7.7 7.7 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2
[131] 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8
[144] 6.8 6.7 6.7 6.3 6.5 6.2 5.9
2.1. Plots in R
boxplot(X$Sepal.Length, main = "Box Plot of the Sepal Length of the IRIS Flowers", col = "blue", horizontal = T)
Error in if (horizontal) plot.window(ylim = xlim, xlim = ylim, log = log, :
the condition has length > 1

The elements of the box-plot are reported below:
- Q1. It is the First Quartile. It leaves
25% of units on the left and 75% of units on the right. Left side of
the box
- Me. It is the Median=Q2. It leaves 50% of
units on left and right. Bold Line in the middle of the
box
- Q3. It is the Third Quartile. It leaves
75% of the units on the left and 25% of the units on the right.
Right side of the box
- In case of no outliers, the whiskers are defined
as:
- Xmin is the left whiskers
- Xmax is the right whiskers
- In case of outliers, the whiskers are defined as:
- Linf = Q1 - 1.5 (Q3-Q1): Lower Limit
- Lsup = Q1 + 1.5 (Q3-Q1): Upper Limit
# just a boxplot
boxplot(X[ ,1:4])

# boxplot with a title and colors
boxplot(X[ ,1:4], main = "Box Plot of all quantitative variables of IRIS data", col = terrain.colors(4))

boxplot(X$Sepal.Width ~ X$Species, main = "Box Plot of Sepal Width considering the 3 types of flowers", xlab = "Type of IRIS Flowers", ylab = "Sepal Width", col = terrain.colors(4))

The tilde symbol is obtained by:
- these doesn’t work [*]:
- MAC: option + 5
- WIN: ALT + 125/6
- these works [*]:
- MAC: shift + button before no.1
- WIN: shift + button before no.1
[ 2.1. BONUS ]
The bold line is the Median, that is the value of
the ordered distribution that leaves the same number of units above and
below (or on left and right)
- Q1 is the first quartile. Q1 leaves 25% of unirs on
left and 75% on right.
- Q3 is the third quartile. Q3 leaves 75% of units on
left and 25% on right.
- Wishers, without outliers are, the min and max of
distribution
- Wishers, with outliers are, Lmin =
Q1-1.5(Q3-Q1); Lsup = Q3+1.5(Q3-Q1);
boxplot(X$Sepal.Length, main = "Box-Plot of the Sepal Lenght", col = "green", horizontal = F)

boxplot(X[ ,1:4], main = "Box-Plot with all the Variables", col = "blue", horizontal = F)

boxplot(X$Sepal.Width ~ X$Species, main = "Box-Plot about Sepal Width with different type of IRIS Flowers")

2.2. Bar Plot
Bar Plot can be used for Qualitative Data and for
Categorized Quantitative Data. The first step to create
a Bar Plot is to generate a Table of Frequency.
T <- table(X$Species)
T
setosa versicolor virginica
50 50 50
barplot(T, main = "Bar Plot of Type of flowers", xlab = "Type of flowers", ylab = "Absolute Frequency", col = terrain.colors(4))

2.3. Pie Chart
It is based on the frequency table.
pie(T, main = "Pie Chart", col = terrain.colors(4))

2.4. Histogram Chart
Histogram is a plot used only for Quantitative Data,
it is based on a frequency tables in classes. The R function is
called hist and the input is a simple distribution of a
quantitative variable.
hist(X$Sepal.Length)

hist(X$Sepal.Width, main = "Histogram of Sepal Width", xlab = "Classes", ylab = "Absolute Frequency", col = "lightgreen", border = "blue")

[ 2.4. BONUS ]
he histogram can be used only for quantitative
variables.
hist(X$Sepal.Width, main = "Histogram of the Sepal Width", xlab = "Classes",
ylab = "Absolute Frequency", col = "green", border = "red", breaks = 10)

In case of equally spaced (same size) classes we can report on the
Y axis the Absolute Frequency or relative frequency. In case of
classes with different sizes we have to report on Y axis the
density of frequency. The formula is the following: \(d_i = n_i/h_i\), where \(n_i\) is the absolute frequency and \(h_i\) is the size of the class.
3. Correlation Analysis
3.1. Correlation Plot
plot(X$Sepal.Length, X$Sepal.Width, main = "Correlation Plot", xlab = "Sepal Length", ylab = "Sepal Width")

[ 3.1. BONUS ]
plot(X$Petal.Length, X$Petal.Width, main = "Correlation Plot",
xlab = "Petal Lenght", ylab = "Petal Width", col = "blue",
pch = 1)

Plots with IRIS
plot(X$Sepal.Length, X$Sepal.Width, main = "(1-2) Plot with IRIS",
xlab = "Sepal Lenght", ylab = "Sepal Width", col = "blue")

plot(X$Petal.Length, X$Petal.Width, main = "(2-2) Plot with IRIS",
xlab = "Petal Lenght", ylab = "Petal Width", col = "red")

3.2. Pair Plot
pairs(X[ ,1:4])

The plots below the main diagonal are the same of the plot above the
main diagonal. The reason is because the plot and the correlation index
are symmetric.
r <- cor(X[ ,1:2])
r <- round(r, 3)
r
Sepal.Length Sepal.Width
Sepal.Length 1.000 -0.118
Sepal.Width -0.118 1.000
cor(X$Sepal.Length, X$Sepal.Width)
[1] -0.1175698
The range of correlation index is: -1 <= r <= 1 The
interpretation of the Correlation Index called
r is following:
- 0.00 < |r| <= 0.25 Low Correlation
- 0.25 < |r| <= 0.50 Medium-Low Correlation
- 0.50 < |r| <= 0.75 Medium-High Correlation
- 0.75 < |r| <= 1.00 High Correlation
- 0 No Correlation
- 1 Perfect Correlation
The correlation between Sepal Length and Sepal
Width is -0.118 and it is a low negative correlation.
4. Plots with GGPLOT Package
install.packages("ggplot2")
Error in install.packages : Updating loaded packages
library(ggplot2)
GGPLOTS has 3 main arguments:
- The first argument is the data: ggplot(data = X). It
creates an empty frame.
- The second argument is the geometry (type of plot): geom_.
It adds a layer with the type of plot we want to show.
- The third argument is the aesthetic, to select the variables and the
properties: mapping = aes()
# GGPLOT (example no 1)
ggplot(data = X[ ,1:2])

# GGPLOT (example no 2.1)
ggplot(data = X[ ,1:2]) +
geom_point(mapping = aes(X$Sepal.Length, X$Sepal.Width))

# GGPLOT (example no 2.2)
ggplot(data = X[ ,1:2]) +
geom_point(mapping = aes(Sepal.Length, Sepal.Width))

# GGPLOT (example no 2.2)
ggplot(data = X) +
geom_point(mapping = aes(Sepal.Length, Sepal.Width))

# GGPLOT (example no 3)
ggplot(data = X) +
geom_point(mapping = aes(Sepal.Length, Sepal.Width)) +
ggtitle("Scatter Plot") + xlab("Sepal Length") + ylab("Sepal Width")

4.1. Correlation Plot (Scatter Plot) with colors
ggplot(data = X) +
geom_point(mapping = aes(Sepal.Length, Sepal.Width, color = Species))

[ 4.1. BONUS ]
STANDARD TEMPLATE IS: ggplot(data = ) +
(mapping = aes())
# First Example
ggplot(data = X) +
geom_point(mapping = aes(Petal.Length, Petal.Width, color = Species)) +
ggtitle("Petal Lenght and Width") +
xlab("Petal Lenght") + ylab("Petal Width")

# Second Example
ggplot(data = X, mapping = aes(Petal.Width, Petal.Length)) +
geom_point(mapping = aes(color = Species)) +
ggtitle("Petal Width and Lenght") +
xlab("Petal Width") + ylab("Petal Lenght")

4.2. Box Plot
ggplot(data = X) +
geom_boxplot(mapping = aes(Sepal.Width), color = "blue", outlier.colour = "red", outlier.shape = 8, outlier.size = 3) +
ggtitle("Box Plot for Sepal Lenght")

Box Plot taking into account the 3 types of flowers
ggplot(data = X) +
geom_boxplot(mapping = aes(Species, Sepal.Width), outlier.color = "red", outlier.shape = 8)

GGPLOT function as object
p <- ggplot(data = X) +
geom_boxplot(mapping = aes(Species, Sepal.Width, fill = Species))
p

p + theme(legend.position = "bottom")

4.3. Bar Plot
ggplot(data = X) +
geom_bar(mapping = aes(Species)) +
ggtitle("Bar Plot with GGPLOT") +
ylab("Absolute Frequency")

5. Use the mpg data (mpg Fuel economy data from 1999 to 2008 for 38
popular model of cars)
A data frame with 234 rows and 11 variables:
- manufacturer brand name
- model model name
- displ engine displacement, in litres (power of the
engine)
- year year of manufacture
- cyl number of cylinders
- trans type of transmission
- drv the type of drive train, where f = front-wheel drive, r
= rear wheel drive, 4 = 4wd
- cty city miles per gallon (km per liter in town)
- hwy highway miles per gallon (km per liter in highway)
- fl fuel type
- class “type” of car
Y <- mpg
summary(Y)
manufacturer model displ
Length:234 Length:234 Min. :1.600
Class :character Class :character 1st Qu.:2.400
Mode :character Mode :character Median :3.300
Mean :3.472
3rd Qu.:4.600
Max. :7.000
year cyl trans
Min. :1999 Min. :4.000 Length:234
1st Qu.:1999 1st Qu.:4.000 Class :character
Median :2004 Median :6.000 Mode :character
Mean :2004 Mean :5.889
3rd Qu.:2008 3rd Qu.:8.000
Max. :2008 Max. :8.000
drv cty hwy
Length:234 Min. : 9.00 Min. :12.00
Class :character 1st Qu.:14.00 1st Qu.:18.00
Mode :character Median :17.00 Median :24.00
Mean :16.86 Mean :23.44
3rd Qu.:19.00 3rd Qu.:27.00
Max. :35.00 Max. :44.00
fl class
Length:234 Length:234
Class :character Class :character
Mode :character Mode :character
head(Y)
5.1. Bar Chart
table(Y$cyl)
4 5 6 8
81 4 79 70
# first example: factor(cyl) as a color ( vertical bar chart )
ggplot(data = Y) +
geom_bar(mapping = aes(cyl, fill = factor(cyl)))

# second example: class as a color ( vertical bar chart )
ggplot(data = Y) +
geom_bar(mapping = aes(cyl, fill = class))

# third example: class instead cyl ( vertical bar chart )
ggplot(data = Y) +
geom_bar(mapping = aes(cyl, fill = class))

# fourth example: class instead cyl ( horizontal bar chart )
ggplot(data = Y) +
geom_bar(mapping = aes(cyl, fill = class)) + coord_flip()

# fifth example: class instead cyl ( horizontal bar chart & legend at the bottom )
ggplot(data = Y) +
geom_bar(mapping = aes(cyl, fill = class)) + coord_flip() + theme(legend.position = "bottom")

5.2. Histogram
# example no 1.1
ggplot(data = Y) +
geom_histogram(mapping = aes(cty))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

# example no 1.2
ggplot(data = Y) +
geom_histogram(mapping = aes(cty, colour = class))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

# example no 1.3
ggplot(data = Y) +
geom_histogram(mapping = aes(cty, fill = class))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

# example no 1.4
ggplot(data = Y) +
geom_histogram(mapping = aes(cty, fill = "red"))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

# example no 1.5
ggplot(data = Y) +
geom_histogram(mapping = aes(cty, fill = factor(cty)))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

# example 2
ggplot(data = Y) +
geom_histogram(mapping = aes(hwy))
`stat_bin()` using `bins = 30`. Pick better value with
`binwidth`.

5.3. Facet Wrap with 1 grup variable [*]
With Facet Wrap layer (option) we can create sub-plots based on a
categorical variable.
ggplot(data = Y) +
geom_point(mapping = aes(displ, hwy)) +
facet_wrap(~drv)

5.4. Facet Wrap with 2 grup variables [*]
ggplot(data = Y) +
geom_point(mapping = aes(displ, hwy)) +
facet_wrap(drv ~ class)

5.5. Smooting Plot [*]
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

5.5.1. Smooting Plot with “different type of line” [*]
# First Example
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy, linetype = class))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
span too small. fewer data values than degrees of freedom.
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
pseudoinverse used at 5.6935
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
neighborhood radius 0.5065
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
reciprocal condition number 0
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
There are other near singularities as well. 0.65044
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
span too small. fewer data values than degrees of freedom.
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
pseudoinverse used at 5.6935
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
neighborhood radius 0.5065
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
reciprocal condition number 0
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
There are other near singularities as well. 0.65044
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
pseudoinverse used at 4.008
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
neighborhood radius 0.708
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
reciprocal condition number 1.6135e-17
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric, :
There are other near singularities as well. 0.25
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
pseudoinverse used at 4.008
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
neighborhood radius 0.708
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
reciprocal condition number 1.6135e-17
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)), :
There are other near singularities as well. 0.25

# Second Example
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy, linetype = drv))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

5.5.2. Smooting Plot with “Facet Wrap” [*]
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy)) +
facet_wrap(~ drv)
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

5.5.3. Smooting Plot with “color” [*]
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy, color = drv))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

5.5.4. Smooting Plot with “group” [*]
ggplot(data = Y) +
geom_smooth(mapping = aes(displ, hwy, group = drv))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

5.5.5. Smooting Plot combining different layers [*]
ggplot(data = Y) +
geom_point(mapping = aes(displ, hwy, color = drv)) +
geom_smooth(mapping = aes(displ, hwy, color = drv))
`geom_smooth()` using method = 'loess' and formula = 'y
~ x'

6. Regression Model [*]
In regression model we need to define the dependent and
independent variables. In our case the model is define as
follow:
- Y(Dependent/Outcome Variable) = hwy. The
variable defines the number of miles (km) per Gallon (liter) on the
highway.
- X(Independent/Input Variable) = displ. The
variable defines the power of the engine (horse power).
In the first place we need to create a scatter plot (correlation
plot).
6.1. Regression Model: Plot [*]
ggplot(data = Y) +
geom_point(mapping = aes(displ, hwy)) +
geom_smooth(method = lm, mapping = aes(displ, hwy))
`geom_smooth()` using formula = 'y ~ x'

6.2. Regression Model: Different Plot per each group [*]
ggplot(data = Y) +
geom_point(mapping = aes(displ, hwy, color = drv)) +
geom_smooth(method = lm, mapping = aes(displ, hwy, color = drv))
`geom_smooth()` using formula = 'y ~ x'

6.3. Regression Model: Parameters Estimation [*]
res.reg <- lm(hwy ~ displ, data = Y)
summary(res.reg)
Call:
lm(formula = hwy ~ displ, data = Y)
Residuals:
Min 1Q Median 3Q Max
-7.1039 -2.1646 -0.2242 2.0589 15.0105
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 35.6977 0.7204 49.55 <2e-16 ***
displ -3.5306 0.1945 -18.15 <2e-16 ***
---
Signif. codes:
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 3.836 on 232 degrees of freedom
Multiple R-squared: 0.5868, Adjusted R-squared: 0.585
F-statistic: 329.5 on 1 and 232 DF, p-value: < 2.2e-16
LS0tCnRpdGxlOiAiTXkgRmlyc3QgTm90ZWJvb2sgTURBMjAyNCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCgojIDEuIERhdGEgRGVzY3JpcHRpb24KCiMjIDEuMS4gU2FtcGxlIFNlbGVjdGVkCgpZb3UgY2FuIGRlZmluZSBidWxsZXQgbGlzdCBvciBudW1iZXJlZCBsaXN0OgoKLSBQaXp6YQotIFBhc3RhCi0gQ2FmZQogIC0gRXNwcmVzc28KICAtIE1hY2NoaWF0bwogIC0gQ2FwcHVjY2lubwotIFZvZGthCiAgLSBCaXNvbnQgR3Jhc3MKICAtIFNvcGxpY2EKCiMjIDEuMi4gRm9ybXVsYQoKSGVyZSB5b3UgY2FuIGRlZmluZSBmb3JtdWxhCgokJCB5ID0gXGJldGFfMCArIFxiZXRhXzFYICsgXGVwc2lsb24gJCQKdGhlIGZvcm11bGEgY2FuIGJlIHJlcG9ydGVkIGluIHRoZSB0ZXh0OiAkXG11ID0gMS9uIFxzdW0gWF9pJAoKIyMgMS4zLiBJbXBvcnQgRGF0YSAoQ1NWKSBbKl0KCmBgYHtyfQpkYXRhX1NEMyA8LSByZWFkLmRlbGltKCJ+L1JQcm9qZWN0cy8yMDI0LVEyLVItMiBbTURBMjAyNCwgZXhlcmNpc2VzXS9EMV9TRDMvZGF0YV9TRDMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycz1UUlVFKQpgYGAKCiMgMi4gRGF0YSBBbmFseXNpcwpUbyBhZGQgUiBjb2RlIGluIHRoZSBOb3RlYm9vayB3ZSBuZWVkIHRvIHVzZSB0aGUgKipDaHVuayoqLgoKYGBge3J9ClggPC0gaXJpcwpgYGAKCkl0IGlzIHBvc3NpYmxlIHRvIGhhdmUgYW4gb3ZlcnZpZXcgb2YgdGhlIGRhdGEgYnkgdXNpbmcgdGhlICpzdW1tYXJ5KiBmdW5jdGlvbi4KCmBgYHtyfQpzdW1tYXJ5KFgpCmBgYApJbiBSIHRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGUgb2YgZGF0YToKCi0gKipNYXRyaXgqKi4gTWF0aGVtYXRpY2FsIE9iamVjdC4gSW4gb3VyIGV4YW1wbGUgKipZKiogaXMgYSBtYXRyaXguCi0gKipEYXRhIEZyYW1lKiouIEl0IGlzIGRldm90ZWQgdG8gb3JnYW5pemUgYW5kIGFuYWx5emUgZGF0YSBhbmQgaXQgaXMgYSBnZW5lcmFsaXphdGlvbiBvZiB0aGUgTWF0cml4LiBJbiBvdXIgZXhhbXBsZSwgKipYKiogaXMgYSBkYXRhIGZyYW1lLgotICoqTGlzdCoqLiBJdCBpcyBhbiBvYmplY3QgdGhhdCBjYW4gaW5jbHVkZSBEYXRhIEZyYW1lcywgTWF0cmljZXMgb3Igb3RoZXIgbGlzdHMuCgpgYGB7cn0KWSA8LSBhcy5tYXRyaXgoWFsgLDE6NF0pCmBgYAoKVG8gaGFuZGxlIGRhdGEgeW91IGNhbiB1c2UgdGhlIGZvbGxvd2luZyBjb2RlOgoKYGBge3J9ClhbMTAsIDJdICAgICAgICMgc2VsZWN0aW9uIG9mIG9uZSBlbGVtZW50IGluIHRoZSBEYXRhIEZyYW1lIChvciBtYXRyaXgpClhbNToyMCwgMTozXSAgICMgc2VsZWN0aW9uIG9mIGFuIGludGVydmFsClhbNToyMCwgXSAgICAgICMgdGhlIGVtcHR5IHNwYWNlIHNlbGVjdCBhbGwgdGhlIGNvbHVtbnMgb3Igcm93cwpYJFNlcGFsLkxlbmd0aCAjIHRoZSBzeW1ib2wgJCBpcyB1c2VkIHRvIHNlbGVjdCBhIGNvbHVtbiBpbiB0aGUgZGF0YSBmcmFtZQpgYGAKIyAyLjEuIFBsb3RzIGluIFIKCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuTGVuZ3RoLCBtYWluID0gIkJveCBQbG90IG9mIHRoZSBTZXBhbCBMZW5ndGggb2YgdGhlIElSSVMgRmxvd2VycyIsIGNvbCA9ICJibHVlIiwgaG9yaXpvbnRhbCA9IFQpCmBgYApUaGUgZWxlbWVudHMgb2YgdGhlIGJveC1wbG90IGFyZSByZXBvcnRlZCBiZWxvdzoKCi0gKipRMSoqLiBJdCBpcyB0aGUgKkZpcnN0IFF1YXJ0aWxlKi4gSXQgbGVhdmVzIDI1JSBvZiB1bml0cyBvbiB0aGUgbGVmdCBhbmQgNzUlIG9mIHVuaXRzIG9uIHRoZSByaWdodC4gKkxlZnQgc2lkZSBvZiB0aGUgYm94KgotICoqTWUqKi4gSXQgaXMgdGhlICpNZWRpYW49UTIqLiBJdCBsZWF2ZXMgNTAlIG9mIHVuaXRzIG9uIGxlZnQgYW5kIHJpZ2h0LiAqQm9sZCBMaW5lIGluIHRoZSBtaWRkbGUgb2YgdGhlIGJveCoKLSAqKlEzKiouIEl0IGlzIHRoZSAqVGhpcmQgUXVhcnRpbGUqLiBJdCBsZWF2ZXMgNzUlIG9mIHRoZSB1bml0cyBvbiB0aGUgbGVmdCBhbmQgMjUlIG9mIHRoZSB1bml0cyBvbiB0aGUgcmlnaHQuICpSaWdodCBzaWRlIG9mIHRoZSBib3gqCi0gSW4gY2FzZSBvZiAqKm5vIG91dGxpZXJzKiosIHRoZSB3aGlza2VycyBhcmUgZGVmaW5lZCBhczoKICAtICoqWG1pbioqIGlzIHRoZSBsZWZ0IHdoaXNrZXJzCiAgLSAqKlhtYXgqKiBpcyB0aGUgcmlnaHQgd2hpc2tlcnMKLSBJbiBjYXNlIG9mICoqb3V0bGllcnMqKiwgdGhlIHdoaXNrZXJzIGFyZSBkZWZpbmVkIGFzOgogIC0gKipMaW5mKiogPSBRMSAtIDEuNSAoUTMtUTEpOiBMb3dlciBMaW1pdAogIC0gKipMc3VwKiogPSBRMSArIDEuNSAoUTMtUTEpOiBVcHBlciBMaW1pdAogIApgYGB7cn0KIyBqdXN0IGEgYm94cGxvdApib3hwbG90KFhbICwxOjRdKQojIGJveHBsb3Qgd2l0aCBhIHRpdGxlIGFuZCBjb2xvcnMKYm94cGxvdChYWyAsMTo0XSwgbWFpbiA9ICJCb3ggUGxvdCBvZiBhbGwgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBvZiBJUklTIGRhdGEiLCBjb2wgPSB0ZXJyYWluLmNvbG9ycyg0KSkKYGBgCiAgCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuV2lkdGggfiBYJFNwZWNpZXMsIG1haW4gPSAiQm94IFBsb3Qgb2YgU2VwYWwgV2lkdGggY29uc2lkZXJpbmcgdGhlIDMgdHlwZXMgb2YgZmxvd2VycyIsIHhsYWIgPSAiVHlwZSBvZiBJUklTIEZsb3dlcnMiLCB5bGFiID0gIlNlcGFsIFdpZHRoIiwgY29sID0gdGVycmFpbi5jb2xvcnMoNCkpCmBgYAoKVGhlICp0aWxkZSBzeW1ib2wqIGlzIG9idGFpbmVkIGJ5OgoKLSB0aGVzZSBkb2Vzbid0IHdvcmsgWypdOgogIC0gTUFDOiBvcHRpb24gKyA1CiAgLSBXSU46IEFMVCArIDEyNS82Ci0gdGhlc2Ugd29ya3MgWypdOgogIC0gTUFDOiBzaGlmdCArIGJ1dHRvbiBiZWZvcmUgbm8uMQogIC0gV0lOOiBzaGlmdCArIGJ1dHRvbiBiZWZvcmUgbm8uMQoKIyMgWyAyLjEuIEJPTlVTIF0KClRoZSBib2xkIGxpbmUgaXMgdGhlICoqTWVkaWFuKiosIHRoYXQgaXMgdGhlIHZhbHVlIG9mIHRoZSBvcmRlcmVkIGRpc3RyaWJ1dGlvbiB0aGF0IGxlYXZlcyB0aGUgc2FtZSBudW1iZXIgb2YgdW5pdHMgYWJvdmUgYW5kIGJlbG93IChvciBvbiBsZWZ0IGFuZCByaWdodCkKCi0gKipRMSoqIGlzIHRoZSBmaXJzdCBxdWFydGlsZS4gUTEgbGVhdmVzIDI1JSBvZiB1bmlycyBvbiBsZWZ0IGFuZCA3NSUgb24gcmlnaHQuCi0gKipRMyoqIGlzIHRoZSB0aGlyZCBxdWFydGlsZS4gUTMgbGVhdmVzIDc1JSBvZiB1bml0cyBvbiBsZWZ0IGFuZCAyNSUgb24gcmlnaHQuCi0gV2lzaGVycywgKip3aXRob3V0IG91dGxpZXJzKiogYXJlLCB0aGUgbWluIGFuZCBtYXggb2YgZGlzdHJpYnV0aW9uCi0gV2lzaGVycywgKip3aXRoIG91dGxpZXJzKiogYXJlLCBMbWluID0gUTEtMS41KihRMy1RMSk7IExzdXAgPSBRMysxLjUqKFEzLVExKTsKCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuTGVuZ3RoLCBtYWluID0gIkJveC1QbG90IG9mIHRoZSBTZXBhbCBMZW5naHQiLCBjb2wgPSAiZ3JlZW4iLCBob3Jpem9udGFsID0gRikKYm94cGxvdChYWyAsMTo0XSwgbWFpbiA9ICJCb3gtUGxvdCB3aXRoIGFsbCB0aGUgVmFyaWFibGVzIiwgY29sID0gImJsdWUiLCBob3Jpem9udGFsID0gRikKYm94cGxvdChYJFNlcGFsLldpZHRoIH4gWCRTcGVjaWVzLCBtYWluID0gIkJveC1QbG90IGFib3V0IFNlcGFsIFdpZHRoIHdpdGggZGlmZmVyZW50IHR5cGUgb2YgSVJJUyBGbG93ZXJzIikKYGBgCgojIDIuMi4gQmFyIFBsb3QKCkJhciBQbG90IGNhbiBiZSB1c2VkIGZvciAqKlF1YWxpdGF0aXZlIERhdGEqKiBhbmQgZm9yICoqQ2F0ZWdvcml6ZWQgUXVhbnRpdGF0aXZlIERhdGEqKi4gVGhlIGZpcnN0IHN0ZXAgdG8gY3JlYXRlIGEgQmFyIFBsb3QgaXMgdG8gZ2VuZXJhdGUgYSAqVGFibGUgb2YgRnJlcXVlbmN5Ki4KCmBgYHtyfQpUIDwtIHRhYmxlKFgkU3BlY2llcykKVApgYGAKCmBgYHtyfQpiYXJwbG90KFQsIG1haW4gPSAiQmFyIFBsb3Qgb2YgVHlwZSBvZiBmbG93ZXJzIiwgeGxhYiA9ICJUeXBlIG9mIGZsb3dlcnMiLCB5bGFiID0gIkFic29sdXRlIEZyZXF1ZW5jeSIsIGNvbCA9IHRlcnJhaW4uY29sb3JzKDQpKQpgYGAKCiMgMi4zLiBQaWUgQ2hhcnQKCkl0IGlzIGJhc2VkIG9uIHRoZSBmcmVxdWVuY3kgdGFibGUuCgpgYGB7cn0KcGllKFQsIG1haW4gPSAiUGllIENoYXJ0IiwgY29sID0gdGVycmFpbi5jb2xvcnMoNCkpCmBgYAoKIyAyLjQuIEhpc3RvZ3JhbSBDaGFydAoKSGlzdG9ncmFtIGlzIGEgcGxvdCB1c2VkIG9ubHkgZm9yICoqUXVhbnRpdGF0aXZlIERhdGEqKiwgaXQgaXMgYmFzZWQgb24gYSBmcmVxdWVuY3kgdGFibGVzIGluIGNsYXNzZXMuIFRoZSAqUiogZnVuY3Rpb24gaXMgY2FsbGVkICpoaXN0KiBhbmQgdGhlIGlucHV0IGlzIGEgc2ltcGxlIGRpc3RyaWJ1dGlvbiBvZiBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4KCmBgYHtyfQpoaXN0KFgkU2VwYWwuTGVuZ3RoKQpgYGAKCmBgYHtyfQpoaXN0KFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiSGlzdG9ncmFtIG9mIFNlcGFsIFdpZHRoIiwgeGxhYiA9ICJDbGFzc2VzIiwgeWxhYiA9ICJBYnNvbHV0ZSBGcmVxdWVuY3kiLCBjb2wgPSAibGlnaHRncmVlbiIsIGJvcmRlciA9ICJibHVlIikKYGBgCgojIyBbIDIuNC4gQk9OVVMgXQoKaGUgaGlzdG9ncmFtIGNhbiBiZSB1c2VkIG9ubHkgZm9yICoqcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyoqLiAKCmBgYHtyfQpoaXN0KFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiSGlzdG9ncmFtIG9mIHRoZSBTZXBhbCBXaWR0aCIsIHhsYWIgPSAiQ2xhc3NlcyIsCiAgICAgeWxhYiA9ICJBYnNvbHV0ZSBGcmVxdWVuY3kiLCBjb2wgPSAiZ3JlZW4iLCBib3JkZXIgPSAicmVkIiwgYnJlYWtzID0gMTApCgpgYGAKCkluIGNhc2Ugb2YgZXF1YWxseSBzcGFjZWQgKHNhbWUgc2l6ZSkgY2xhc3NlcyB3ZSBjYW4gcmVwb3J0IG9uIHRoZSAqWSogYXhpcyB0aGUgQWJzb2x1dGUgRnJlcXVlbmN5IG9yIHJlbGF0aXZlIGZyZXF1ZW5jeS4gSW4gY2FzZSBvZiBjbGFzc2VzIHdpdGggZGlmZmVyZW50IHNpemVzIHdlIGhhdmUgdG8gcmVwb3J0IG9uICpZKiBheGlzIHRoZSAqZGVuc2l0eSBvZiBmcmVxdWVuY3kqLiBUaGUgZm9ybXVsYSBpcyB0aGUgZm9sbG93aW5nOiAkZF9pID0gbl9pL2hfaSQsIHdoZXJlICRuX2kkIGlzIHRoZSBhYnNvbHV0ZSBmcmVxdWVuY3kgYW5kICRoX2kkIGlzIHRoZSBzaXplIG9mIHRoZSBjbGFzcy4KCiMgMy4gQ29ycmVsYXRpb24gQW5hbHlzaXMKCiMjIDMuMS4gQ29ycmVsYXRpb24gUGxvdAoKYGBge3J9CnBsb3QoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiQ29ycmVsYXRpb24gUGxvdCIsIHhsYWIgPSAiU2VwYWwgTGVuZ3RoIiwgeWxhYiA9ICJTZXBhbCBXaWR0aCIpCmBgYAoKIyMgWyAzLjEuIEJPTlVTIF0KCmBgYHtyfQpwbG90KFgkUGV0YWwuTGVuZ3RoLCBYJFBldGFsLldpZHRoLCBtYWluID0gIkNvcnJlbGF0aW9uIFBsb3QiLAogICAgIHhsYWIgPSAiUGV0YWwgTGVuZ2h0IiwgeWxhYiA9ICJQZXRhbCBXaWR0aCIsIGNvbCA9ICJibHVlIiwKICAgICBwY2ggPSAxKQpgYGAKClBsb3RzIHdpdGggSVJJUwoKYGBge3J9CnBsb3QoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiKDEtMikgUGxvdCB3aXRoIElSSVMiLCAKICAgICB4bGFiID0gIlNlcGFsIExlbmdodCIsIHlsYWIgPSAiU2VwYWwgV2lkdGgiLCBjb2wgPSAiYmx1ZSIpCnBsb3QoWCRQZXRhbC5MZW5ndGgsIFgkUGV0YWwuV2lkdGgsIG1haW4gPSAiKDItMikgUGxvdCB3aXRoIElSSVMiLCAKICAgICB4bGFiID0gIlBldGFsIExlbmdodCIsIHlsYWIgPSAiUGV0YWwgV2lkdGgiLCBjb2wgPSAicmVkIikKYGBgCgojIyAzLjIuIFBhaXIgUGxvdAoKYGBge3J9CnBhaXJzKFhbICwxOjRdKQpgYGAKClRoZSBwbG90cyBiZWxvdyB0aGUgbWFpbiBkaWFnb25hbCBhcmUgdGhlIHNhbWUgb2YgdGhlIHBsb3QgYWJvdmUgdGhlIG1haW4gZGlhZ29uYWwuIFRoZSByZWFzb24gaXMgYmVjYXVzZSB0aGUgcGxvdCBhbmQgdGhlIGNvcnJlbGF0aW9uIGluZGV4IGFyZSBzeW1tZXRyaWMuCgpgYGB7cn0KciA8LSBjb3IoWFsgLDE6Ml0pCnIgPC0gcm91bmQociwgMykKcgpjb3IoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgpCgpgYGAKClRoZSByYW5nZSBvZiBjb3JyZWxhdGlvbiBpbmRleCBpczogKi0xIDw9IHIgPD0gMSoKVGhlIGludGVycHJldGF0aW9uIG9mIHRoZSAqQ29ycmVsYXRpb24gSW5kZXgqIGNhbGxlZCAqKnIqKiBpcyBmb2xsb3dpbmc6CgotIDAuMDAgPCB8cnwgPD0gMC4yNSAqTG93IENvcnJlbGF0aW9uKgotIDAuMjUgPCB8cnwgPD0gMC41MCAqTWVkaXVtLUxvdyBDb3JyZWxhdGlvbioKLSAwLjUwIDwgfHJ8IDw9IDAuNzUgKk1lZGl1bS1IaWdoIENvcnJlbGF0aW9uKgotIDAuNzUgPCB8cnwgPD0gMS4wMCAqSGlnaCBDb3JyZWxhdGlvbioKLSAwICpObyBDb3JyZWxhdGlvbioKLSAxICpQZXJmZWN0IENvcnJlbGF0aW9uKgoKVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gKlNlcGFsIExlbmd0aCogYW5kICpTZXBhbCBXaWR0aCogaXMgLTAuMTE4IGFuZCBpdCBpcyBhIGxvdyBuZWdhdGl2ZSBjb3JyZWxhdGlvbi4KCiMgNC4gUGxvdHMgd2l0aCBHR1BMT1QgUGFja2FnZQoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKR0dQTE9UUyBoYXMgMyBtYWluIGFyZ3VtZW50czoKCi0gVGhlIGZpcnN0IGFyZ3VtZW50IGlzIHRoZSBkYXRhOiAqZ2dwbG90KGRhdGEgPSBYKSouIEl0IGNyZWF0ZXMgYW4gZW1wdHkgZnJhbWUuCi0gVGhlIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgZ2VvbWV0cnkgKHR5cGUgb2YgcGxvdCk6ICpnZW9tXyouIEl0IGFkZHMgYSBsYXllciB3aXRoIHRoZSB0eXBlIG9mIHBsb3Qgd2Ugd2FudCB0byBzaG93LgotIFRoZSB0aGlyZCBhcmd1bWVudCBpcyB0aGUgYWVzdGhldGljLCB0byBzZWxlY3QgdGhlIHZhcmlhYmxlcyBhbmQgdGhlIHByb3BlcnRpZXM6ICptYXBwaW5nID0gYWVzKCkqCgpgYGB7cn0KIyBHR1BMT1QgKGV4YW1wbGUgbm8gMSkKZ2dwbG90KGRhdGEgPSBYWyAsMToyXSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMi4xKQpnZ3Bsb3QoZGF0YSA9IFhbICwxOjJdKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFgkU2VwYWwuTGVuZ3RoLCBYJFNlcGFsLldpZHRoKSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMi4yKQpnZ3Bsb3QoZGF0YSA9IFhbICwxOjJdKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgpKQojIEdHUExPVCAoZXhhbXBsZSBubyAyLjIpCmdncGxvdChkYXRhID0gWCkgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhTZXBhbC5MZW5ndGgsIFNlcGFsLldpZHRoKSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMykKZ2dwbG90KGRhdGEgPSBYKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgpKSArCiAgZ2d0aXRsZSgiU2NhdHRlciBQbG90IikgKyB4bGFiKCJTZXBhbCBMZW5ndGgiKSArIHlsYWIoIlNlcGFsIFdpZHRoIikKYGBgCgojIyA0LjEuIENvcnJlbGF0aW9uIFBsb3QgKFNjYXR0ZXIgUGxvdCkgd2l0aCBjb2xvcnMKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoU2VwYWwuTGVuZ3RoLCBTZXBhbC5XaWR0aCwgY29sb3IgPSBTcGVjaWVzKSkKYGBgCgojIyBbIDQuMS4gQk9OVVMgXQoKKipTVEFOREFSRCBURU1QTEFURSBJUzoqKgogIGdncGxvdChkYXRhID0gPERBVEE+KSArIAogIDxHRU9NX0ZVTkNUSU9OPihtYXBwaW5nID0gYWVzKDxNQVBQSU5HUz4pKQoKYGBge3J9CiMgRmlyc3QgRXhhbXBsZQpnZ3Bsb3QoZGF0YSA9IFgpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFBldGFsLkxlbmd0aCwgUGV0YWwuV2lkdGgsIGNvbG9yID0gU3BlY2llcykpICsKICBnZ3RpdGxlKCJQZXRhbCBMZW5naHQgYW5kIFdpZHRoIikgKwogIHhsYWIoIlBldGFsIExlbmdodCIpICsgeWxhYigiUGV0YWwgV2lkdGgiKQojIFNlY29uZCBFeGFtcGxlCmdncGxvdChkYXRhID0gWCwgbWFwcGluZyA9IGFlcyhQZXRhbC5XaWR0aCwgUGV0YWwuTGVuZ3RoKSkgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBTcGVjaWVzKSkgKwogIGdndGl0bGUoIlBldGFsIFdpZHRoIGFuZCBMZW5naHQiKSArIAogIHhsYWIoIlBldGFsIFdpZHRoIikgKyB5bGFiKCJQZXRhbCBMZW5naHQiKQpgYGAKCiMjIDQuMi4gQm94IFBsb3QKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyhTZXBhbC5XaWR0aCksIGNvbG9yID0gImJsdWUiLCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiLCBvdXRsaWVyLnNoYXBlID0gOCwgb3V0bGllci5zaXplID0gMykgKwogIGdndGl0bGUoIkJveCBQbG90IGZvciBTZXBhbCBMZW5naHQiKQpgYGAKCkJveCBQbG90IHRha2luZyBpbnRvIGFjY291bnQgdGhlIDMgdHlwZXMgb2YgZmxvd2VycwoKYGBge3J9CmdncGxvdChkYXRhID0gWCkgKwogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKFNwZWNpZXMsIFNlcGFsLldpZHRoKSwgb3V0bGllci5jb2xvciA9ICJyZWQiLCBvdXRsaWVyLnNoYXBlID0gOCkKYGBgCgpHR1BMT1QgZnVuY3Rpb24gYXMgb2JqZWN0CgpgYGB7cn0KcCA8LSBnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyhTcGVjaWVzLCBTZXBhbC5XaWR0aCwgZmlsbCA9IFNwZWNpZXMpKQpwCnAgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgojIyA0LjMuIEJhciBQbG90CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBYKSArIAogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoU3BlY2llcykpICsgCiAgZ2d0aXRsZSgiQmFyIFBsb3Qgd2l0aCBHR1BMT1QiKSArIAogIHlsYWIoIkFic29sdXRlIEZyZXF1ZW5jeSIpCmBgYAoKIyA1LiBVc2UgdGhlIG1wZyBkYXRhIChtcGcgRnVlbCBlY29ub215IGRhdGEgZnJvbSAxOTk5IHRvIDIwMDggZm9yIDM4IHBvcHVsYXIgbW9kZWwgb2YgY2FycykKCkEgZGF0YSBmcmFtZSB3aXRoIDIzNCByb3dzIGFuZCAxMSB2YXJpYWJsZXM6CgotICptYW51ZmFjdHVyZXIqIGJyYW5kIG5hbWUKLSAqbW9kZWwqIG1vZGVsIG5hbWUKLSAqZGlzcGwqIGVuZ2luZSBkaXNwbGFjZW1lbnQsIGluIGxpdHJlcyAocG93ZXIgb2YgdGhlIGVuZ2luZSkKLSAqeWVhciogeWVhciBvZiBtYW51ZmFjdHVyZQotICpjeWwqIG51bWJlciBvZiBjeWxpbmRlcnMKLSAqdHJhbnMqIHR5cGUgb2YgdHJhbnNtaXNzaW9uCi0gKmRydiogdGhlIHR5cGUgb2YgZHJpdmUgdHJhaW4sIHdoZXJlIGYgPSBmcm9udC13aGVlbCBkcml2ZSwgciA9IHJlYXIgd2hlZWwgZHJpdmUsIDQgPSA0d2QKLSAqY3R5KiBjaXR5IG1pbGVzIHBlciBnYWxsb24gKGttIHBlciBsaXRlciBpbiB0b3duKQotICpod3kqIGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbiAoa20gcGVyIGxpdGVyIGluIGhpZ2h3YXkpCi0gKmZsKiBmdWVsIHR5cGUKLSAqY2xhc3MqICJ0eXBlIiBvZiBjYXIKCmBgYHtyfQpZIDwtIG1wZwpgYGAKCmBgYHtyfQpzdW1tYXJ5KFkpCmhlYWQoWSkKYGBgCgojIyA1LjEuIEJhciBDaGFydAoKYGBge3J9CnRhYmxlKFkkY3lsKQpgYGAKCmBgYHtyfQojIGZpcnN0IGV4YW1wbGU6IGZhY3RvcihjeWwpIGFzIGEgY29sb3IgKCB2ZXJ0aWNhbCBiYXIgY2hhcnQgKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGZhY3RvcihjeWwpKSkKIyBzZWNvbmQgZXhhbXBsZTogY2xhc3MgYXMgYSBjb2xvciAoIHZlcnRpY2FsIGJhciBjaGFydCApCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoY3lsLCBmaWxsID0gY2xhc3MpKQojIHRoaXJkIGV4YW1wbGU6IGNsYXNzIGluc3RlYWQgY3lsICggdmVydGljYWwgYmFyIGNoYXJ0ICkKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyhjeWwsIGZpbGwgPSBjbGFzcykpCiMgZm91cnRoIGV4YW1wbGU6IGNsYXNzIGluc3RlYWQgY3lsICggaG9yaXpvbnRhbCBiYXIgY2hhcnQgKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGNsYXNzKSkgKyBjb29yZF9mbGlwKCkKIyBmaWZ0aCBleGFtcGxlOiBjbGFzcyBpbnN0ZWFkIGN5bCAoIGhvcml6b250YWwgYmFyIGNoYXJ0ICYgbGVnZW5kIGF0IHRoZSBib3R0b20gKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGNsYXNzKSkgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgojIyA1LjIuIEhpc3RvZ3JhbQoKYGBge3J9CiMgZXhhbXBsZSBubyAxLjEKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHkpKQojIGV4YW1wbGUgbm8gMS4yCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoY3R5LCBjb2xvdXIgPSBjbGFzcykpCiMgZXhhbXBsZSBubyAxLjMKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSBjbGFzcykpCiMgZXhhbXBsZSBubyAxLjQKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSAicmVkIikpCiMgZXhhbXBsZSBubyAxLjUKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSBmYWN0b3IoY3R5KSkpCiMgZXhhbXBsZSAyCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoaHd5KSkKYGBgCgojIyA1LjMuIEZhY2V0IFdyYXAgd2l0aCAxIGdydXAgdmFyaWFibGUgWypdCgpXaXRoIEZhY2V0IFdyYXAgbGF5ZXIgKG9wdGlvbikgd2UgY2FuIGNyZWF0ZSBzdWItcGxvdHMgYmFzZWQgb24gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpICsKICBmYWNldF93cmFwKH5kcnYpCmBgYAoKIyMgNS40LiBGYWNldCBXcmFwIHdpdGggMiBncnVwIHZhcmlhYmxlcyBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpICsKICBmYWNldF93cmFwKGRydiB+IGNsYXNzKQpgYGAKCiMjIDUuNS4gU21vb3RpbmcgUGxvdCBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3kpKQpgYGAKCiMjIyA1LjUuMS4gU21vb3RpbmcgUGxvdCB3aXRoICJkaWZmZXJlbnQgdHlwZSBvZiBsaW5lIiBbKl0KCmBgYHtyfQojIEZpcnN0IEV4YW1wbGUKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5LCBsaW5ldHlwZSA9IGNsYXNzKSkKIyBTZWNvbmQgRXhhbXBsZQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGxpbmV0eXBlID0gZHJ2KSkKYGBgCgojIyMgNS41LjIuIFNtb290aW5nIFBsb3Qgd2l0aCAiRmFjZXQgV3JhcCIgWypdCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5KSkgKwogIGZhY2V0X3dyYXAofiBkcnYpCmBgYAoKIyMjIDUuNS4zLiBTbW9vdGluZyBQbG90IHdpdGggImNvbG9yIiBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGNvbG9yID0gZHJ2KSkKYGBgCgojIyMgNS41LjQuIFNtb290aW5nIFBsb3Qgd2l0aCAiZ3JvdXAiIFsqXQoKYGBge3J9CmdncGxvdChkYXRhID0gWSkgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgZ3JvdXAgPSBkcnYpKQpgYGAKCiMjIyA1LjUuNS4gU21vb3RpbmcgUGxvdCBjb21iaW5pbmcgZGlmZmVyZW50IGxheWVycyBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgY29sb3IgPSBkcnYpKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5LCBjb2xvciA9IGRydikpCmBgYAoKIyA2LiBSZWdyZXNzaW9uIE1vZGVsIFsqXQoKSW4gcmVncmVzc2lvbiBtb2RlbCB3ZSBuZWVkIHRvIGRlZmluZSB0aGUgKmRlcGVuZGVudCogYW5kICppbmRlcGVuZGVudCogdmFyaWFibGVzLiBJbiBvdXIgY2FzZSB0aGUgbW9kZWwgaXMgZGVmaW5lIGFzIGZvbGxvdzoKCi0gKlkoRGVwZW5kZW50L091dGNvbWUgVmFyaWFibGUpKiA9ICoqaHd5KiouIFRoZSB2YXJpYWJsZSBkZWZpbmVzIHRoZSBudW1iZXIgb2YgbWlsZXMgKGttKSBwZXIgR2FsbG9uIChsaXRlcikgb24gdGhlIGhpZ2h3YXkuCi0gKlgoSW5kZXBlbmRlbnQvSW5wdXQgVmFyaWFibGUpKiA9ICoqZGlzcGwqKi4gVGhlIHZhcmlhYmxlIGRlZmluZXMgdGhlIHBvd2VyIG9mIHRoZSBlbmdpbmUgKGhvcnNlIHBvd2VyKS4KCkluIHRoZSBmaXJzdCBwbGFjZSB3ZSBuZWVkIHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCAoY29ycmVsYXRpb24gcGxvdCkuCgojIyA2LjEuIFJlZ3Jlc3Npb24gTW9kZWw6IFBsb3QgWypdCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3kpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpCmBgYAoKIyMgNi4yLiBSZWdyZXNzaW9uIE1vZGVsOiBEaWZmZXJlbnQgUGxvdCBwZXIgZWFjaCBncm91cCBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgY29sb3IgID0gZHJ2KSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGNvbG9yID0gZHJ2KSkKCmBgYAoKIyMgNi4zLiBSZWdyZXNzaW9uIE1vZGVsOiBQYXJhbWV0ZXJzIEVzdGltYXRpb24gWypdCgpgYGB7cn0KcmVzLnJlZyA8LSBsbShod3kgfiBkaXNwbCwgZGF0YSA9IFkpCnN1bW1hcnkocmVzLnJlZykKYGBgCgoKCg==